午安~昨天建了一個Reagent App,也開啟好了專案起始頁面,是一個里程碑!
但身為工程師的我們,可不會僅止步於此啦~
除了用clojure(結合clojure生態系的套件hiccup)寫幾個html tag(例如::h1
、:p
)來顯示單純字串之外,
還可能會有以下需求
顯示上的變化
增加自己的component
增加新的頁面和連結
,且每個頁面都可以套用2.
所說的component因此,對應以上需求,我思考了以下三點的學習目標,為我們專案增加一些變化~
1. 介紹clojure(script)語法,且將效果顯示在前端
2. 如何建立自己的component,這樣以後就可以重複利用這些元件囉
3. 也會稍微帶到App裡使用的reitit.frontend套件for route及程式碼
今天是週六,先來第一個輕鬆的主題:
看到首頁畫面上比昨天多了一組Day06 - Maps的collection:
key分別為:hello
與 :cat
,
其中:cat
的value看起來是遞增的元素,從(一隻貓)變成(兩隻貓)變成(三隻貓)變成(四隻貓),看起來是分別回傳像list的LazySeq,最後再全部裝到一個LazySeq
如果這是一個clojure kata,語法要怎麼寫出來呢?
1到4
的數字sequence顯示1-4,以數字表達會用 (range 1 5)
map
回傳當看到回傳結果是裝在小括號內的 (LazySeq)
腦袋馬上聯想到Day08 - clojure functional programming的map
(map #(str "Good Morning, " %) ["Goma" "Cara"])
=> ("Good Morning, Goma" "Good Morning, Cara")
因此複習map用法 (map f coll)
之後
大概會寫出一下的架構
(map (f) (range 1 5))
因此接下來就要進行到重點了: 拼湊匿名函式
我每次執行一次某個function,
function就會幫我把數字產生到對應的貓數量
constantly
: 給我貓貓,其餘免談來新學一個constantly
語意上是不變的
。
constantly returns a function which always returns the same value
例如:雙十節快到了,用def
產生一個double-ten
的值always 1010
(def double-ten (constantly 1010))
(double-ten 1111)
=> 1010
(double-ten 1212)
=> 1010
(double-ten :zzz)
=> 1010
總之不管怎樣就是回傳同樣的值就對了
舉一反三到我們前端顯示的頁面,constantly
用想辦法印出貓
(def two-cats (constantly '??))
(defn home-page []
(fn []
[:span.main
[:h1 "Welcome to Ting's"]
[:h1 "2022 IT Ironman project "]
[:div
[:h4 "I am Ironman."]
[:p
[:h3 (two-cats 1)]
[:h3 (two-cats 100)]]]]))
畫面如下:
無論 (two-cats 1)
(two-cats 100)
帶了什麼參數,回傳都只會有兩隻貓~
comp
:來新學一個comp
comp字義是composition
合成物,會幫我們回傳一組function
comp usage
(comp)(comp f)(comp f g)(comp f g & fs)
Takes a set of functions
and returns a fn that is the composition of those fns.
The returned fn takes a variable number of args,
applies the rightmost of fns to the args,
the next fn (right-to-left) to the result, etc.
舉個例子練習一下,定義一個 cat-map
,裡面是一個槽狀Map
(def cat-map {:hello {:cat 2}})
(:cat (:hello cat-map))
;;=> 2
;;
((comp :cat :hello) cat-map)
;;=> 2
(:cat (:hello cat-map))
這一句是說把cat-map裡的 :hello
的值拿出來,為 {:cat 2}}
再把:cat
的值拿出來,return為2
(comp :cat :hello)
會從最右邊開始當第一個fn
、再來是右邊第二個fn
,變成回傳一組fn
那cat-map拿去以上的組合fn做操作,結果還是2
最後,回到本題的開頭,遞增的貓貓要怎麼出現在頁面上呢?
(map (comp #(map (constantly '?) %) range) (range 1 5))
整個前端的頁面code長這樣(變得無比花俏:P):
(def cats (constantly '??))
(defn home-page []
(fn []
[:span.main
[:h1 "Welcome to Ting's"]
[:h1 "2022 IT Ironman project "]
[:div
[:h4 "I am Ironman."]
[:p
[:h3 (cats 1)]
[:h3 (cats 100)]
"I have a " [:strong "bold"]
[:span {:style {:color "red"}} " heart!"]]]
{:hello "? Good morning my love" :cat (map (comp #(map (constantly '?) %) range) (range 1 5))}
[:ul
[:li [:a {:href (path-for :items)} "My IronProject"]]
[:li [:a {:href "/broken/link"} "Articles link "]]]
]))
後來經過前輩提醒,發現之前有用的repeat也可以做到一樣的效果
repeat usage
(repeat x)(repeat n x)
Returns a lazy (infinite!, or length n if supplied) sequence of xs.
(take 5 (repeat "cat"))
=> ("cat" "cat" "cat" "cat" "cat")
;; 與上列相同
(repeat 5 "cat")
=> ("cat" "cat" "cat" "cat" "cat")
;; 回傳遞增數量的"cat"
(map #(repeat % "cat") (range 1 5))
=> (("cat") ("cat" "cat") ("cat" "cat" "cat") ("cat" "cat" "cat" "cat"))
不用再寫一次range (用%代替) ,也不用再用composite起來所有的function
把這個概念套用在前端,來簡化一點語法
本篇文章inspired by clerk這個套件
Clerk enables a rich, local-first notebook experience using standard Clojure namespaces and Markdown files with Clojure code fences. You bring your own editor and workflow, your own interactive computing habits, and Clerk enhances all of that with literate programming and rich visualizations.
看了套件簡介之後,發現這個套件可以做到文學程式設計(英語:literate programming)用人類日常使用的語言寫出自由地表達邏輯,就好像一篇文章一樣。
example:
(def notebooks
(clojure.java.io/file "notebooks"))
(into #{} (map str) (file-seq notebooks))
result:
#{
"notebooks"
"notebooks/controls.clj"
"notebooks/data_science.clj"
"notebooks/elements.clj"
;;...
}
而Reagent app裡竟然預設就有裝了這個套件,
因此就拿clerk文件裡其中一個範例改編一下,把範例設為回傳貓貓emoji來玩玩看囉!
希望大家也會跟我一樣,覺得學新東西是件有趣的事情~:D
明天接著來講解研究以下兩點!
2. App專案要既然是前端框架,也要能夠`增加自己的component`
3. App專案要能夠`增加新的頁面和連結`,且每個頁面都可以套用`2.`所說的component